home *** CD-ROM | disk | FTP | other *** search
/ SuperHack / SuperHack CD.bin / CODING / WINDOWS / CTRL2CAP.ZIP / CTRL2CAP.C next >
Encoding:
C/C++ Source or Header  |  1996-12-08  |  9.0 KB  |  331 lines

  1. //======================================================================
  2. //
  3. // ctrl2cap.c
  4. //
  5. // Copyright (C) 1996 Mark Russinovich
  6. //
  7. // Hook onto the keyboard I/O path and massage the input stream
  8. // converting caps-locks into controls
  9. //
  10. //======================================================================
  11. #include "ntddk.h"
  12. #include "stdarg.h"
  13. #include "stdio.h"
  14. #include "ctrl2cap.h"
  15. #include "ntddkbd.h"
  16.  
  17. // print macro that only turns on when checked builds are on
  18. #if DBG
  19. #define DbgPrint(arg) DbgPrint arg
  20. #else
  21. #define DbgPrint(arg)
  22. #endif
  23.  
  24. NTSYSAPI
  25. VOID
  26. NTAPI
  27. HalDisplayString( PCHAR String );
  28.  
  29.  
  30. //----------------------------------------------------------------------
  31. //                         GLOBALS
  32. //---------------------------------------------------------------------- 
  33. PDEVICE_OBJECT       kbdDevice;
  34. PDEVICE_OBJECT       HookDeviceObject;
  35.  
  36. //----------------------------------------------------------------------
  37. //                         FORWARD DEFINES
  38. //---------------------------------------------------------------------- 
  39. NTSTATUS Ctrl2capDispatchRead( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp );
  40. NTSTATUS Ctrl2capDispatchGeneral(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp );
  41. NTSTATUS Ctrl2capInit( IN PDRIVER_OBJECT DriverObject );
  42.  
  43.  
  44. //----------------------------------------------------------------------
  45. //
  46. // DriverEntry
  47. //
  48. // Installable driver initialization. Here we just set ourselves up.
  49. //
  50. //----------------------------------------------------------------------
  51. NTSTATUS DriverEntry(
  52.     IN PDRIVER_OBJECT  DriverObject,
  53.     IN PUNICODE_STRING RegistryPath )
  54. {
  55.     PDEVICE_OBJECT         deviceObject        = NULL;
  56.     NTSTATUS               ntStatus;
  57.     WCHAR                  deviceNameBuffer[]  = L"\\Device\\Ctrl2cap";
  58.     UNICODE_STRING         deviceNameUnicodeString;
  59.     WCHAR                  deviceLinkBuffer[]  = L"\\DosDevices\\Ctrl2cap";
  60.     UNICODE_STRING         deviceLinkUnicodeString;
  61.  
  62.     DbgPrint (("Ctrl2cap.SYS: entering DriverEntry\n"));
  63.  
  64.     //
  65.     // Create our device.
  66.     //
  67.         
  68.     RtlInitUnicodeString (&deviceNameUnicodeString,
  69.                           deviceNameBuffer );
  70.     
  71.     ntStatus = IoCreateDevice (DriverObject,
  72.                                0,
  73.                                &deviceNameUnicodeString,
  74.                                FILE_DEVICE_CTRL2CAP,
  75.                                0,
  76.                                TRUE,
  77.                                &deviceObject );
  78.  
  79.     if (NT_SUCCESS(ntStatus)) {
  80.  
  81.      //
  82.      // Create a symbolic link so that ctr2lcap can be dynamically loaded.
  83.          //
  84.  
  85.      RtlInitUnicodeString (&deviceLinkUnicodeString,
  86.                    deviceLinkBuffer );
  87.      ntStatus = IoCreateSymbolicLink (&deviceLinkUnicodeString,
  88.                       &deviceNameUnicodeString );
  89.      if (!NT_SUCCESS(ntStatus))
  90.           DbgPrint (("Ctrl2cap.SYS: IoCreateSymbolicLink failed\n"));
  91.  
  92.      //
  93.      // Create dispatch points for all the IRPs the keyboard class device
  94.          // handles.
  95.          //
  96.  
  97.       DriverObject->MajorFunction[IRP_MJ_READ]        
  98.                = Ctrl2capDispatchRead;
  99.      DriverObject->MajorFunction[IRP_MJ_CREATE]         =
  100.      DriverObject->MajorFunction[IRP_MJ_CLOSE]          =
  101.      DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS]  =
  102.      DriverObject->MajorFunction[IRP_MJ_CLEANUP]        =
  103.      DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] 
  104.                        = Ctrl2capDispatchGeneral;
  105.     }
  106.  
  107.     if (!NT_SUCCESS(ntStatus)) {
  108.  
  109.      //
  110.      // Something went wrong, so clean up (free resources etc)
  111.      //
  112.  
  113.          if (deviceObject )
  114.           IoDeleteDevice (deviceObject);
  115.     }
  116.  
  117.     return Ctrl2capInit( DriverObject );
  118. }
  119.  
  120.  
  121. //----------------------------------------------------------------------
  122. //
  123. // Ctrl2capInit
  124. //
  125. // Hook onto the keyboard's path. Why does this routine return
  126. // status success even if there's a problem? I've found that if it 
  127. // doesn't, the keyboard won't respond!
  128. //
  129. //----------------------------------------------------------------------
  130. NTSTATUS Ctrl2capInit( IN PDRIVER_OBJECT DriverObject )
  131. {
  132.     CCHAR         ntNameBuffer[64];
  133.     STRING         ntNameString;
  134.     UNICODE_STRING       ntUnicodeString;
  135.     NTSTATUS             status;
  136.  
  137.     //
  138.     // Only hook onto the first keyboard's chain.
  139.     //
  140.  
  141.     sprintf( ntNameBuffer, "\\Device\\KeyboardClass0" );
  142.     RtlInitAnsiString( &ntNameString, ntNameBuffer );
  143.     RtlAnsiStringToUnicodeString( &ntUnicodeString, &ntNameString, TRUE );
  144.  
  145.     //
  146.     // Create device object for the keyboard.
  147.     //
  148.  
  149.     status = IoCreateDevice( DriverObject,
  150.                  0,
  151.                  NULL,
  152.                  FILE_DEVICE_KEYBOARD,
  153.                  0,
  154.                  FALSE,
  155.                  &HookDeviceObject );
  156.  
  157.     if( !NT_SUCCESS(status) ) {
  158.  
  159.      DbgPrint(("Ctrl2cap: Keyboard hook failed to create device!\n"));
  160.  
  161.      RtlFreeUnicodeString( &ntUnicodeString );
  162.  
  163.      return STATUS_SUCCESS;
  164.     }
  165.    
  166.     //
  167.     // Keyboard uses buffered I/O so we must as well.
  168.     //
  169.  
  170.     HookDeviceObject->Flags |= DO_BUFFERED_IO;
  171.  
  172.     //
  173.     // Attach to the keyboard chain.
  174.     //
  175.  
  176.     status = IoAttachDevice( HookDeviceObject, &ntUnicodeString, &kbdDevice );
  177.  
  178.     if( !NT_SUCCESS(status) ) {
  179.  
  180.      DbgPrint(("Ctrl2cap: Connect with keyboard failed!\n"));
  181.  
  182.      IoDeleteDevice( HookDeviceObject );
  183.  
  184.      RtlFreeUnicodeString( &ntUnicodeString );
  185.     
  186.      return STATUS_SUCCESS;
  187.     }
  188.  
  189.     //
  190.     // Done! Just free our string and be on our way...
  191.     //
  192.  
  193.     RtlFreeUnicodeString( &ntUnicodeString );
  194.  
  195.     DbgPrint(("Ctrl2cap: Successfully connected to keyboard device\n"));
  196.  
  197.     //
  198.     // This line simply demonstrates how a driver can print
  199.     // stuff to the bluescreen during system initialization.
  200.     //
  201.   
  202.     HalDisplayString( "Ctrl2cap Initialized\n" );
  203.  
  204.     return STATUS_SUCCESS;
  205. }
  206.  
  207. //----------------------------------------------------------------------
  208. // 
  209. // Ctrl2capReadComplete
  210. //
  211. // Gets control after a read operation has completed.
  212. //
  213. //----------------------------------------------------------------------
  214. NTSTATUS Ctrl2capReadComplete( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp,
  215.                 IN PVOID Context )
  216. {
  217.     PIO_STACK_LOCATION        IrpSp;
  218.     PKEYBOARD_INPUT_DATA      KeyData;
  219.  
  220.     //
  221.     // Request completed - look at the result.
  222.     //
  223.  
  224.     IrpSp = IoGetCurrentIrpStackLocation( Irp );
  225.     if( NT_SUCCESS( Irp->IoStatus.Status ) ) {
  226.  
  227.         //
  228.     // Do caps-lock down and caps-lock up. Note that
  229.         // just frobbing the MakeCode handles both the up-key
  230.         // and down-key cases since the up/down information is specified
  231.         // seperately in the Flags field of the keyboard input data 
  232.         // (0 means key-down, 1 means key-up).
  233.         //
  234.  
  235.       KeyData = Irp->AssociatedIrp.SystemBuffer;
  236.  
  237.         DbgPrint(("ScanCode: %x ", KeyData->MakeCode ));
  238.         DbgPrint(("%s\n", KeyData->Flags ? "Up" : "Down" ));
  239.  
  240.     if( KeyData->MakeCode == CAPS_LOCK) {
  241.  
  242.         KeyData->MakeCode = LCONTROL;
  243.  
  244.         } 
  245.     }
  246.  
  247.     if( Irp->PendingReturned ) {
  248.  
  249.         IoMarkIrpPending( Irp );
  250.  
  251.     }
  252.  
  253.     return Irp->IoStatus.Status;
  254. }
  255.  
  256.  
  257. //----------------------------------------------------------------------
  258. //
  259. // Ctrl2capDispatchRead
  260. //
  261. // Sets up to look at the read request completion so that we can
  262. // massage the input queue on IO completion.
  263. //
  264. //----------------------------------------------------------------------
  265. NTSTATUS Ctrl2capDispatchRead( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp )
  266. {
  267.     PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
  268.     PIO_STACK_LOCATION nextIrpStack    = IoGetNextIrpStackLocation(Irp);
  269.  
  270.     //
  271.     // Push params down for keyboard class driver.
  272.     //
  273.  
  274.     *nextIrpStack = *currentIrpStack;
  275.  
  276.     //  
  277.     // Set the completion callback, so we can "frob" the keyboard data.
  278.     //        
  279.  
  280.     IoSetCompletionRoutine( Irp, Ctrl2capReadComplete, DeviceObject, TRUE, TRUE, TRUE );
  281.  
  282.     //
  283.     // Return the results of the call to the keyboard class driver.
  284.     //
  285.         
  286.     return IoCallDriver( kbdDevice, Irp );
  287. }
  288.  
  289.  
  290. //----------------------------------------------------------------------
  291. //
  292. // Ctrl2capDispatchGeneral
  293. //
  294. // This handles several functions we are not interested in 
  295. // along to the keyboard class driver. 
  296. //
  297. //----------------------------------------------------------------------
  298. NTSTATUS Ctrl2capDispatchGeneral(
  299.     IN PDEVICE_OBJECT DeviceObject,
  300.     IN PIRP           Irp )
  301. {
  302.     PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
  303.     PIO_STACK_LOCATION nextIrpStack    = IoGetNextIrpStackLocation(Irp);
  304.  
  305.     //
  306.     // Default to success.
  307.     //
  308.  
  309.     Irp->IoStatus.Status      = STATUS_SUCCESS;
  310.     Irp->IoStatus.Information = 0;
  311.  
  312.     //
  313.     // If this call was directed at the hook device, pass it to 
  314.     // the keyboard class device, else handle it ourselves.
  315.     // 
  316.  
  317.    if( DeviceObject == HookDeviceObject ) {
  318.  
  319.        *nextIrpStack = *currentIrpStack;
  320.  
  321.        return IoCallDriver( kbdDevice, Irp );
  322.  
  323.    } else {
  324.  
  325.        return STATUS_SUCCESS;
  326.  
  327.    }
  328. }
  329.  
  330.  
  331.